#include <stdlib.h>
#include <string.h>

static void __copy(void * e1, void * e2, long int size);
static void __gqsort(void * data, int lo, int ho, long int unit_size, int (*compare)(void * e1, void * e2));

void gqsort(void * base, long int total_elements, long int unit_size, int (*compare)(void * e1, void * e2)) {

    long int lo;
    long int ho;

    lo = 0;
    ho = total_elements - 1;

    __gqsort(base, lo, ho, unit_size, compare);

}

static void __copy(void * e1, void * e2, long int size) {
    long int i;

    char * b1 = e1;
    char * b2 = e2;

    for (i = 0; i < size; i++) {
        *b1 = *b2;
        b1++;
        b2++;
    }
}

static void __gqsort(void * data, int lo, int ho, long int unit_size, int (*compare)(void * e1, void * e2)) {

    /* Elements */
    void * pivot;
    void * left;
    void * right;
    void * tmp;

    /* Indexes */
    long int l, h, pi;

    tmp = calloc(1, unit_size);

    l = lo;
    h = ho;

    if (ho > lo) {

        pi = (lo + ho) >> 1;
        pivot = data + (pi * unit_size);

        left = data + (l * unit_size);
        while ((l < ho) && (compare(left, pivot) < 0)) {
            l++;
            left = data + (l * unit_size);
        }

        right = data + (h * unit_size);
        while ((h > lo) && (compare(right, pivot) > 0)) {
            h--;
            right = data + (h * unit_size);
        }

        if (l <= h) {
            //strncpy(tmp, left, unit_size);
            //strncpy(left, right, unit_size);
            //strncpy(right, tmp, unit_size);
            __copy(tmp, left, unit_size);
            __copy(left, right, unit_size);
            __copy(right, tmp, unit_size);
            l++;
            h--;
        }
        free(tmp);
        if (lo < h) __gqsort(data, lo, h, unit_size, compare);
        if (l < ho) __gqsort(data, l, ho, unit_size, compare);
    }
}
